package com.haohan.task;

import com.haohan.config.ThreadPoolConfig;
import com.haohan.constant.MachineStateCode;
import com.haohan.domain.ServerInfo;
import com.haohan.service.ServerInfoService;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.PumpStreamHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.*;
import java.util.List;
import java.util.concurrent.Executor;

/**
 * @author: jzhou
 * @date: 2024/12/22-19:33
 * @version: 1.0
 * @description: compass
 */
@Slf4j
//@Component
public class RunningTimeTask {

    @Autowired
    private ServerInfoService serverInfoService;

    @Resource(name = ThreadPoolConfig.RUNNING_TIME_EXECUTOR_POOL)
    private Executor runningTimeExecutorPool;

    int port = 22; // SSH 默认端口
    @Scheduled(fixedRate = 1000 * 60 * 5) // 每五分钟执行一次
    public void run() throws Exception {

        // 获取全部数据
        List<ServerInfo> serverInfos = serverInfoService.list();
//        ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
        for (ServerInfo serverInfo : serverInfos) {
            runningTimeExecutorPool.execute(() -> updateServerRunTime(serverInfo));
        }
    }


    public void updateServerRunTime(ServerInfo serverInfo) {


        if (isReachable(serverInfo)) {
            serverInfo.setStatus(MachineStateCode.RUNNING);
            serverInfo.setRunTime(null);
            Session session = null;
            ChannelExec channelExec = null;
            try {
                JSch jsch = new JSch();
                session = jsch.getSession(serverInfo.getUsername(), serverInfo.getServerIp(), port);
                session.setPassword(serverInfo.getPassword());

                // 禁用主机密钥检查，这在生产环境中是不推荐的，应该使用更安全的方法处理主机密钥
                session.setConfig("StrictHostKeyChecking", "no");

                session.connect(1000);

                channelExec = (ChannelExec) session.openChannel("exec");
                channelExec.setCommand("uptime -p");

                InputStream in = channelExec.getInputStream();
                channelExec.connect();

                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                String line;
                while ((line = reader.readLine()) != null) {
                    if (line.startsWith("up")) {
                        // 提取开机时间
                        String uptime = line.split("up ")[1].replaceAll(",","");
                        log.info("{} is up and running for: {}", serverInfo.getServerIp(), uptime);
                        serverInfo.setRunTime(uptime);
                        break;
                    }
                }

            } catch (Exception e) {
                log.error("Failed to connect to {}", serverInfo.getServerIp(), e);
                serverInfo.setStatus(MachineStateCode.UNKNOWN);
                serverInfo.setRemark(MachineStateCode.UNKNOWN_REASON);
            } finally {
                if (channelExec != null && channelExec.isConnected()) {
                    channelExec.disconnect();
                }
                if (session != null && session.isConnected()) {
                    session.disconnect();
                }
            }
        }else{
            serverInfo.setStatus(MachineStateCode.SHOWDOWN);
        }
        log.info(serverInfo.toString());
        serverInfoService.updateById(serverInfo);
    }



    private static boolean isReachable(ServerInfo serverInfo) {
        CommandLine commandLine = new CommandLine("ping");
        commandLine.addArgument(serverInfo.getServerIp());
        // 判断操作系统
        if (System.getProperty("os.name").toLowerCase().contains("win")) {
            commandLine.addArgument("-n").addArgument("1"); // For Windows
        } else {
            commandLine.addArgument("-c").addArgument("1"); // For Linux/Mac
        }

        org.apache.commons.exec.Executor executor = new DefaultExecutor();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream,null);
        executor.setExitValues(null); // Accept all exit values
        executor.setStreamHandler(streamHandler);

        try {
            int exitCode = executor.execute(commandLine);
//            String output = outputStream.toString("GBK");
//            log.info("Ping output: {}", output);
            log.info("Ping exit code: {}", exitCode);
            return exitCode == 0;
        } catch (ExecuteException e) {
            log.error("ExecuteException ping command: {}", e.getMessage());
            return false;
        } catch (IOException e) {
            log.error("IOException executing ping command: {}", e.getMessage());
            return false;
        }

    }
}
